/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package controller;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.SQLException;
import static java.util.Collections.list;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.internet.AddressException;
import model.* ;
import view.ControlPanel;

/**
 *
 * @author mona
 */
public class ChatServerImpl extends UnicastRemoteObject implements ChatServerInt
{
    Map<String,ClientInt> allclients;
    DatabaseConnection db;
    
    BufferedOutputStream out;
    ControlPanel cp ;
    
    public ChatServerImpl() throws RemoteException { 
        
        super();
        
        allclients = new HashMap<>(); 

        try{            
            
            db = new DatabaseConnection("root","asmaaelmasry");
            
        }catch(ClassNotFoundException | IllegalAccessException | InstantiationException | SQLException e){
            System.out.println("Cann't connect to database .. check username and password");
          
        }
        
    }
    
    @Override
    public User getMyUser(String myUserName) throws RemoteException{
        try {
            return db.getUserInfo(myUserName);
        } catch (SQLException ex) {
            System.out.println("Can't get Your UserName");
        }
        return null;
    }

    @Override
    public int controlFriendRelation(String senderUsername , String recieverUserName,int action)  throws RemoteException{
        int queryStatus = 0 ;
        try {
            if(action == 0){ 
                // add         
                queryStatus = db.addFriend(db.getId(senderUsername), db.getId(recieverUserName));

                if(allclients.containsKey(recieverUserName)){
                    System.out.println(recieverUserName+" "+senderUsername);
                    allclients.get(recieverUserName).checkFriendReqs();
                }
            }else if(action == 1){
                // accept
                queryStatus = db.acceptFriend(db.getId(senderUsername), db.getId(recieverUserName));
                //allclients.get(recieverUserName).friendReqAccepted(getMyUser(senderUsername));
                allclients.get(senderUsername).friendReqAccepted(getMyUser(recieverUserName));
            }else{
                // reject
                queryStatus = db.deleteFriend(db.getId(senderUsername), db.getId(recieverUserName));
            }
            
        } catch (SQLException ex) {
           System.out.println("Can't Control Friend Relation");
             
        }
        return queryStatus;
    }

    
    public int signUp(String email,String name,String password,String userName,String country,String gender)
    {
        try
        {
            if(db.getEmail(email)== 0 && db.getUserName(userName)==0)
            {
                int m =db.register(name, email, userName, password, country,gender);
                System.out.println(m);
                return m;
                
            }
            else
            {
                System.out.println("Already exists");
            }
        }
        catch(Exception e)
        {
            System.out.println("Server problem in Sign Up");
            
        }
        return 0;
        
    }
    @Override
    public ClientInt returnUsers(String userName) {
       
        ClientInt userRef = allclients.get(userName);
        
        return userRef;
    }
    
    @Override
    public int signIn(String userName , String password, ClientInt clientRef) throws RemoteException{
        try{
            if(db.checkSignIn(userName, password) == 1)
            {
                allclients.put(userName, clientRef);
                cp.updateLabels();
                return 1;
            }
            return 0;           
        }catch(SQLException e){
             System.out.println("Can't Connect to Database for Sign In");
            
        }
        
        return 0;
    }
    
    
    @Override
    public User[] getFriends(String userName , String password , int reqStatus) throws RemoteException{
        try {
            if(db.checkSignIn(userName, password) == 1 ){
                
                User[] friends = db.getFriends(db.getId(userName),reqStatus);

                if(friends != null && reqStatus != 0){
                    for (User user : friends) {
                        if(allclients.containsKey(user.getUserName())){
                            try {
                                allclients.get(user.getUserName()).updateFriendStatus(userName, 1);
                            } catch (RemoteException ex) {
                                System.out.println("Can't Reach Client "+user.getUserName());
                            }
                        }                           
                    }
                }
                return friends;
            }    
        } catch (SQLException ex) {
            System.out.println("Can't Connect to Database  to get Friend list when sign in");
        }
        return null;
    }
       
    
    @Override
    public boolean signOut(String userName)  throws RemoteException{
        try {
            allclients.remove(userName);
            //System.out.println("Client "+ userName+" removed");
            db.logOut(userName);
            updateStatus(userName, 0);
            cp.updateLabels();
            return  true;
        } catch (SQLException ex) {
            System.out.println("Can't Sign Out problem in Database");
            
        }
        return false;       
    }
    
    @Override
    public void updateStatus(String userName, int _status)  throws RemoteException{
        try {
            db.setStatus(userName, _status);
            User[] friends  = db.getFriends(db.getId(userName),1);
            if(friends != null ){
                for (User user : friends) {
                    if(allclients.containsKey(user.getUserName()))
                        allclients.get(user.getUserName()).updateFriendStatus(userName, _status);
                }
            }
            
        } catch (SQLException ex) {
            System.out.println("Can't update Status");
            
        }  
                
    }

    @Override
    public int startConference(String[] friends,int numberOfConf,String userNameWhoSentReq) {
        try {
            
            String userIdWhoSentReq = String.valueOf(db.getId(userNameWhoSentReq));
            int confId = Integer.valueOf(userIdWhoSentReq + numberOfConf);
            Vector<ClientInt> clients = new Vector<>();
            for (String friend : friends) {
                clients.add(allclients.get(friend));
            }
            
            clients.add(allclients.get(userNameWhoSentReq));
            
            ClientInt[] clientsArr = new ClientInt[clients.size()];
            
            clients.toArray(clientsArr);
            
            String[] friendsTemp = new String[friends.length + 1];
                
            for (int i = 0 ; i < friends.length ; i++ ) {
                friendsTemp[i] = friends[i];
            }
                
            friendsTemp[friends.length] = userNameWhoSentReq;
                
            friends = friendsTemp;
            
            
            for (ClientInt client : clientsArr) {
                try {
                    client.startConference(friends,clientsArr, confId);
                } catch (RemoteException ex) {
                    System.out.println("Can't Add user");
                }
            }
            
            return confId;
            
        } catch (SQLException ex) {
            System.out.println("Can't connect to database to start Coneference");
             
        }
        
        return 0;
    }
    
  public int sendMail (String senderMail , String[] receiverMail , String subject , String text) throws RemoteException
  {
        try {
            MailHandler mh = new MailHandler();
            int y = mh.oneToMany(senderMail, receiverMail , subject, text);
            
            //System.out.println(y);
            return y ;
        } catch (AddressException ex) {
            System.out.println("Can't send mail");
        }      
        return 0;
  
  }
  
    @Override
  public boolean addFriendBefore(String myUsername , String friendUserName) throws RemoteException{
        try {
            int result = db.getReqStatus(db.getId(myUsername), db.getId(friendUserName)); 

            if(result == -1)
                return false;
            else
                return true;
            
        } catch (SQLException ex) {
            System.out.println("Problem in Adding Friend ");
        }
        return false;
  }
  

    public int countOnlineUsers() {

        int c = allclients.size();
        return c;

    }

    public int countOfflineUsers() {
        int all = db.countAllUsers();
        int offline = all - countOnlineUsers();
        return offline;

    }

    void setControlPanel(ControlPanel cp) {
    
        this.cp  = cp ; 
    }
    
    public void sendAds(String messagee){
        for(Map.Entry<String,ClientInt> client : allclients.entrySet() )
            {
                try
                {
                    client.getValue().receiveAd(messagee);
                
                }catch(RemoteException ex){
                
                    System.out.println(" Can't Send Add to  Client "+client.getKey());
                    //ex.printStackTrace();                
                }
            }    
    }
    
    public void shutDownUsers(){
        //System.out.println(allclients.size());
        
       Iterator it = allclients.entrySet().iterator();
       
       while (it.hasNext()) {
            Map.Entry pairs = (Map.Entry)it.next();
            try {
                ((ClientInt)pairs.getValue()).shutdown();
                db.setStatus((String)pairs.getKey(), 0);
                System.out.println(pairs.getKey());
            } catch (RemoteException ex) {
                 System.out.println(" Can't Close Client "+ pairs.getKey());
            }
            
            it.remove(); // avoids a ConcurrentModificationException
       }  
       //System.out.println("after"+allclients.size());
       allclients.clear();
    }
  
  /*
  @Override
    public void startStream(File fileName) throws RemoteException {
        try {
            out=new BufferedOutputStream(new FileOutputStream(fileName));
        } catch (FileNotFoundException ex) {
            System.out.println("File Not Found");
        }
        //return out;
    }

    @Override
    public void closeStream() throws RemoteException {
       try {
            out.close();
        } catch (IOException ex) {
            System.out.println("IOServer");
        }
    }
    */    
        /*public void sendAdvertise(String toUserName, String msg)
        {
            System.out.println("Messge received: "+msg);
            
            for(Map.Entry<String,ClientInt> client : allclients.entrySet() )
            {
                try
                {
                    client.getValue().receive(msg);
                
                }catch(RemoteException ex){
                
                    System.out.println("Can’t send msg to client!");
                    ex.printStackTrace();                
                }
            }
        }*/

    
}

